package com.ruoyi.system.service.impl;

import java.util.*;
import java.util.stream.Collectors;

import com.ruoyi.common.constant.*;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.*;
import com.ruoyi.common.utils.security.Md5Utils;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.mapper.*;
import com.ruoyi.system.service.ISysConfigService;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.system.service.ISysTenantService;
import com.ruoyi.common.core.text.Convert;
import org.springframework.util.StringUtils;

/**
 * 租户信息Service业务层处理
 * 
 * @author kuaidou
 * @date 2021-08-20
 */
@Service
public class SysTenantServiceImpl implements ISysTenantService {
    @Autowired
    private SysTenantMapper sysTenantMapper;

    @Autowired
    private SysApplicationMapper sysApplicationMapper;

    @Autowired
    private SysTenantApplicationMapper sysTenantApplicationMapper;

    @Autowired
    private SysDeptMapper sysDeptMapper;

    @Autowired
    private SysRoleMapper sysRoleMapper;

    @Autowired
    private SysRoleDeptMapper sysRoleDeptMapper;

    @Autowired
    private SysMenuMapper sysMenuMapper;

    @Autowired
    private SysRoleMenuMapper sysRoleMenuMapper;

    @Autowired
    private ISysConfigService sysConfigService;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;

    /**
     * 查询租户信息
     *
     * @param id 租户信息主键
     * @return 租户信息
     */
    @Override
    public SysTenant selectSysTenantById(Long id) {
        return sysTenantMapper.selectSysTenantById(id);
    }

    /**
     * 查询租户信息
     *
     * @param tenantCode 租户信息编号
     * @return 租户信息
     */
    @Override
    public SysTenant selectTenantByTenantCode(String tenantCode) {
        return sysTenantMapper.selectTenantByTenantCode(tenantCode);
    }

    /**
     * 查询租户信息列表
     *
     * @param sysTenant 租户信息
     * @return 租户信息
     */
    @Override
    public List<SysTenant> selectSysTenantList(SysTenant sysTenant) {
        return sysTenantMapper.selectSysTenantList(sysTenant);
    }

    /**
     * 新增租户信息
     *
     * @param sysTenant 租户信息
     * @return 结果
     */
    @Override
    public int insertSysTenant(SysTenant sysTenant) {
        sysTenant.setCreateTime(DateUtils.getNowDate());
        SysTenantApplication sysTenantApplication = new SysTenantApplication();
        sysTenantApplication.setTenantCode(sysTenant.getTenantCode());
        Map<String, Integer> appCodeFreeDateMaps = new TreeMap<>();
        Map<String, Date> appCodeMaps = new TreeMap<>();
        List<String> appCodes = new ArrayList<>();
        SysApplication sysApplication = new SysApplication();
        sysApplication.setAppType(sysTenant.getType());
        List<SysApplication> sysApplications = sysApplicationMapper.selectSysApplicationAuthList(sysApplication);
        if (!sysApplications.isEmpty()) {
            appCodes= sysApplications.stream().map(SysApplication::getAppCode).collect(Collectors.toList());
            appCodeFreeDateMaps = sysApplications.stream().collect(Collectors.toMap(SysApplication::getAppCode, SysApplication::getFreeDate));

        }
        for (String appCode : appCodeFreeDateMaps.keySet()) {
            Integer freeDate = appCodeFreeDateMaps.get(appCode);
            if (freeDate != null && freeDate > 0) {
                appCodeMaps.put(appCode, DateUtils.addDays(DateUtils.getNowDate(), freeDate));
            } else {
                appCodeMaps.put(appCode, DateUtils.addDays(DateUtils.getNowDate(), Constants.DAYS));
            }

        }
        sysTenantApplication.setAppCodes(appCodes);
        sysTenantApplication.setAppCodeMaps(appCodeMaps);
        authApplication(sysTenantApplication, sysTenant);
        return sysTenantMapper.insertSysTenant(sysTenant);
    }

    /**
     * 修改租户信息
     *
     * @param sysTenant 租户信息
     * @return 结果
     */
    @Override
    public int updateSysTenant(SysTenant sysTenant) {
        sysTenant.setUpdateTime(DateUtils.getNowDate());
        return sysTenantMapper.updateSysTenant(sysTenant);
    }

    /**
     * 批量删除租户信息
     *
     * @param ids 需要删除的租户信息主键
     * @return 结果
     */
    @Override
    public int deleteSysTenantByIds(String ids) {
        int i = sysTenantMapper.deleteSysTenantByIds(Convert.toStrArray(ids));
        if(i>0){
            sysUserMapper.deleteUserNoTenant();
        }
        return i;
    }

    /**
     * 删除租户信息信息
     *
     * @param id 租户信息主键
     * @return 结果
     */
    @Override
    public int deleteSysTenantById(Long id) {
        int i = sysTenantMapper.deleteSysTenantById(id);
        if(i>0){
            sysUserMapper.deleteUserNoTenant();
        }
        return i;
    }

    /**
     * 租户分配子系统
     *
     * @param tenantApplication
     * @return
     */
    @Override
    public int authApplication(SysTenantApplication tenantApplication, SysTenant tenant) {
        //查询该租户信息
        SysTenant sysTenant = selectTenantByTenantCode(tenantApplication.getTenantCode());
        //先查询该租户是否分配了子系统
        List<SysTenantApplication> sysTenantApplicationList = sysTenantApplicationMapper.selectSysTenantApplicationByTenantCode(tenantApplication.getTenantCode());
        if (sysTenant == null || CollectionUtils.isEmpty(sysTenantApplicationList)) {
            // 说明是新用户
            //只在第一次分配系统时创建
            //添加关联租户关联系统
            sysTenantApplicationMapper.batchTenantApplication(tenantApplication.getTenantCode(), tenantApplication.getAppCodeMaps());
            //创建部门
            SysDept dept = new SysDept();
            //父级部门
            dept.setParentId(new Long(0));
            dept.setDeptName(tenant.getTenantName());
            dept.setAncestors("0");
            dept.setTenantCode(tenant.getTenantCode());
            dept.setOrderNum("0");
            dept.setLeader(tenant.getContactMan());
            dept.setPhone(tenant.getContactNumber());
            sysDeptMapper.insertDept(dept);
            //创建角色
            SysRole role = new SysRole();
            role.setRoleName(tenant.getTenantName() + "_管理员");
            role.setRoleKey(tenant.getTenantCode() + RoleKeyConstants.ADMIN);
            role.setRoleSort("1");
            role.setDataScope(DataScopeConstants.ALL);
            role.setStatus("0");
            role.setTenantCode(tenant.getTenantCode());
            role.setRemark(tenant.getTenantName() + "_管理员");
            sysRoleMapper.insertRole(role);
            //创建角色关联部门
            List<SysRoleDept> roleDeptList = getSysRoleDepts(dept, role);
            sysRoleDeptMapper.batchRoleDept(roleDeptList);
            //添加角色关联菜单
            List<SysRole> roles = new ArrayList<>();
            roles.add(role);
            insertMenuRoles(tenantApplication.getAppCodes(), roles);
            //创建用户
            SysUser user = new SysUser();
            user.setDeptId(dept.getDeptId());
            user.setLoginName(tenant.getContactNumber());
            user.setUserName(tenant.getContactMan());
            user.setTenantCode(tenant.getTenantCode());
            user.setUserType(tenant.getType());
            user.setPhonenumber(tenant.getContactNumber());
            user.setSex("0");
            user.setSalt(ShiroUtils.randomSalt());
            user.setNetid(CodeGenerateUtils.netIdGenerate());
            user.setPassword(Md5Utils.hash(tenant.getContactNumber() + sysConfigService.selectConfigByKey(Constants.SYS_USER_INITPASSWORD) + user.getSalt()));
            user.setPwdUpdateDate(DateUtils.getNowDate());
            sysUserMapper.insertUser(user);
            //添加用户归属角色
            List<SysUserRole> userRoles = getSysUserRoles(role, user);
            sysUserRoleMapper.batchUserRole(userRoles);
            //TODO 帮租户创建工作人员角色,分配所有除按钮之外的菜单
            SysRole gzry = new SysRole();
            gzry.setRoleName(tenant.getTenantName() + "_工作人员");
            gzry.setRoleKey(tenant.getTenantCode() + RoleKeyConstants.JOB);
            gzry.setRoleSort("5");
            gzry.setDataScope(DataScopeConstants.DEPARTMENT_BELOW);
            gzry.setStatus("0");
            gzry.setCreateBy(tenant.getCreateBy());
            gzry.setTenantCode(tenant.getTenantCode());
            sysRoleMapper.insertRole(gzry);
            //创建角色关联部门
            List<SysRoleDept> gzryRoleDeptList = getSysRoleDepts(dept, gzry);
            sysRoleDeptMapper.batchRoleDept(gzryRoleDeptList);
            //添加角色关联菜单
            List<SysRole> gzryRoles = new ArrayList<>();
            gzryRoles.add(gzry);
            insertMenuRolesNoButton(tenantApplication.getAppCodes(), gzryRoles);
            //TODO 帮租户创建普通用户角色,暂时未有菜单分配
            SysRole sysRole = new SysRole();
            sysRole.setRoleName(tenant.getTenantName() + "_普通用户");
            sysRole.setRoleKey(tenant.getTenantCode() + RoleKeyConstants.USER);
            sysRole.setRoleSort("10");
            sysRole.setDataScope(DataScopeConstants.ONESELF);
            sysRole.setStatus("0");
            sysRole.setTenantCode(tenant.getTenantCode());
            sysRoleMapper.insertRole(sysRole);
        } else {
            // 第二次授权
            List<SysRole> sysRoles = sysRoleMapper.selectSysRoleByTenantCode(tenantApplication.getTenantCode());
            //存新增的,获取新的
            Map<String, Date> newAppCodeMaps = tenantApplication.getAppCodeMaps();
            //存废除的,获取废除事物
            List<String> oldAppCodes = sysTenantApplicationList.stream().map(SysTenantApplication::getAppCode).collect(Collectors.toList());
            //清空旧的角色关联的菜单和关联租户
            if (!CollectionUtils.isEmpty(oldAppCodes)) {
                deleteRoleMensTenantOld(tenantApplication.getTenantCode(), oldAppCodes, sysRoles);
            }
            //编辑时添加新的系统关联信息
            if (!CollectionUtils.isEmpty(newAppCodeMaps)) {
                //添加关联租户关联系统
                sysTenantApplicationMapper.batchTenantApplication(tenantApplication.getTenantCode(), newAppCodeMaps);
                //添加角色关联的菜单
                List<SysRole> adminRoles = new ArrayList<>();
                List<SysRole> gzryRoles = new ArrayList<>();
                for (SysRole sr : sysRoles) {
                    if (sr.getRoleKey().contains("_admin")) {
                        adminRoles.add(sr);
                    }
                    if (sr.getRoleKey().contains("_gzry")) {
                        gzryRoles.add(sr);
                    }
                }
                // TODO 其它角色需要重新授权
                // 管理员的
                insertMenuRoles(tenantApplication.getAppCodes(), adminRoles);
                //工作人员的
                insertMenuRolesNoButton(tenantApplication.getAppCodes(), gzryRoles);
            }
        }
        return 1;
    }

    /**
     * 查找注册用户可授权应用
     *
     * @param sysApplication 系统应用信息
     * @return
     */
    @Override
    public List<SysApplication> selectSysApplicationAuthList(SysApplication sysApplication) {
        return sysApplicationMapper.selectSysApplicationAuthList(sysApplication);
    }

    private List<SysRoleDept> getSysRoleDepts(SysDept dept, SysRole role) {
        List<SysRoleDept> roleDeptList = new ArrayList<>();
        SysRoleDept roleDept = new SysRoleDept();
        roleDept.setDeptId(dept.getDeptId());
        roleDept.setRoleId(role.getRoleId());
        roleDeptList.add(roleDept);
        return roleDeptList;
    }

    private List<SysUserRole> getSysUserRoles(SysRole role, SysUser user) {
        List<SysUserRole> userRoles = new ArrayList<>();
        SysUserRole userRole = new SysUserRole();
        userRole.setRoleId(role.getRoleId());
        userRole.setUserId(user.getUserId());
        userRoles.add(userRole);
        return userRoles;
    }

    /**
     * 根据系统添加角色与菜单的关联
     *
     * @param appCodes
     * @param roles
     */
    private void insertMenuRoles(List<String> appCodes, List<SysRole> roles) {
        Map<String, List<SysMenu>> appCodeMaps = sysMenuMapper.selectMenuAll().stream().filter(sysMenu -> appCodes.contains(sysMenu.getAppCode())).collect(Collectors.groupingBy(SysMenu::getAppCode));
        for (String appCode : appCodes) {
            List<SysMenu> sysMenus = appCodeMaps.get(appCode);
            if (sysMenus != null && sysMenus.size() > 0 && roles != null && roles.size() > 0) {
                batchRolesmenus(roles, sysMenus);
            }
        }
    }

    private void batchRolesmenus(List<SysRole> roles, List<SysMenu> sysMenus) {
        List<SysRoleMenu> sysRoleMenus = new ArrayList();
        for (SysRole role : roles) {
            for (SysMenu menu : sysMenus) {
                SysRoleMenu sysRoleMenu = new SysRoleMenu();
                sysRoleMenu.setMenuId(menu.getMenuId());
                sysRoleMenu.setRoleId(role.getRoleId());
                sysRoleMenus.add(sysRoleMenu);
            }
        }
        sysRoleMenuMapper.batchRoleMenu(sysRoleMenus);
    }

    /**
     * 根据系统添加角色与菜单的关联(按钮不添加)
     *
     * @param appCodes
     * @param roles
     */
    private void insertMenuRolesNoButton(List<String> appCodes, List<SysRole> roles) {
        for (String appCode : appCodes) {
            List<SysMenu> sysMenus = sysMenuMapper.setectMenuByAppCodeNoButton(appCode);
            if (sysMenus != null && sysMenus.size() > 0 && roles != null && roles.size() > 0) {
                batchRolesmenus(roles, sysMenus);
            }
        }
    }

    /**
     * 删除角色跟菜单的关联
     *
     * @param tenantCode
     * @param appCodes
     * @param sysRoles
     */
    private void deleteRoleMensTenantOld(String tenantCode, List<String> appCodes, List<SysRole> sysRoles) {
        for (String appCode : appCodes) {
            sysTenantApplicationMapper.deleteTenantApplicationByTenantCode(tenantCode, appCode);
            List<SysMenu> sysMenus = sysMenuMapper.setectMenuByAppCode(appCode);
            if (sysMenus != null && sysMenus.size() > 0 && sysRoles != null && sysRoles.size() > 0) {
                for (SysRole role : sysRoles) {
                    sysRoleMenuMapper.deleteRoleMenusAndRoleId(sysMenus, role.getRoleId());
                }
            }

        }
    }
}